//package com.lu.model;
//
//import cn.hutool.core.date.DatePattern;
//import cn.hutool.core.date.DateUtil;
//import cn.hutool.core.io.FileUtil;
//import cn.hutool.core.lang.Assert;
//import cn.hutool.core.util.ObjectUtil;
//import cn.hutool.core.util.RandomUtil;
//import cn.hutool.core.util.StrUtil;
//import com.usthe.bootshiro.config.file.SysFileConfig;
//import com.usthe.bootshiro.constants.RedisKey;
//import com.usthe.bootshiro.domain.vo.Message;
//import com.usthe.bootshiro.es.constants.enums.EsIndexTypeEnum;
//import com.usthe.bootshiro.es.domain.Keywords;
//import com.usthe.bootshiro.es.exception.EsModularException;
//import com.usthe.bootshiro.es.mapper.KeywordsMapper;
//import com.usthe.bootshiro.es.service.KnowledgeService;
//import com.usthe.bootshiro.es.util.JestSearchUtil;
//import com.usthe.bootshiro.es.util.JestUpdateDocUtil;
//import com.usthe.bootshiro.service.FileService;
//import com.usthe.bootshiro.util.*;
//import io.searchbox.core.SearchResult;
//import lombok.extern.slf4j.Slf4j;
//import org.elasticsearch.common.lucene.search.function.CombineFunction;
//import org.elasticsearch.index.query.BoolQueryBuilder;
//import org.elasticsearch.index.query.QueryBuilder;
//import org.elasticsearch.index.query.QueryBuilders;
//import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder;
//import org.elasticsearch.search.builder.SearchSourceBuilder;
//import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.data.redis.core.StringRedisTemplate;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//import org.springframework.web.multipart.MultipartFile;
//import tk.mybatis.mapper.entity.Example;
//import tk.mybatis.mapper.util.Sqls;
//
//import java.io.File;
//import java.util.*;
//import java.util.concurrent.atomic.AtomicInteger;
//
///**
// * @author leesineesin
// * @date 2020/4/30
// */
//@Slf4j
//@Service
//public class KnowledgeServiceImpl implements KnowledgeService {
//
//    private static final String INVALID = "0";
//
//    private static final String UN_INVALID = "1";
//
//    @Autowired
//    private KeywordsMapper keywordsMapper;
//
//    @Autowired
//    private JestUpdateDocUtil jestUpdateDocUtil;
//
//    @Autowired
//    private JestSearchUtil jestSearchUtil;
//
//    @Autowired
//    private StringRedisTemplate stringRedisTemplate;
//
//    @Autowired
//    private RedisTemplate redisTemplate;
//
//    @Autowired
//    private SysFileConfig sysFileConfig;
//
//    @Autowired
//    private FileService fileService;
//
//    @Override
//    public Message knowledgePageList(Integer page, Integer limit, String searchWords,String invalid) {
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        //构建 关键词匹配
//        BoolQueryBuilder boolQueryBuilderAll = new BoolQueryBuilder();
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        if(ObjectUtil.isNotEmpty(searchWords)){
//            boolQueryBuilder.should((QueryBuilders.matchQuery("title", searchWords).boost(4)))
//                    .should((QueryBuilders.matchQuery("outline", searchWords).boost(2)))
//                    .should((QueryBuilders.matchQuery("content", searchWords).boost(1)));
//        }
//        //如果参数不为空且为失效
//        if (!ObjectUtil.isEmpty(invalid) && INVALID.equals(invalid)){
//            boolQueryBuilderAll.must(QueryBuilders.matchPhraseQuery("invalid","0")).must(boolQueryBuilder);
//        } else if (ObjectUtil.isEmpty(invalid) || UN_INVALID.equals(invalid)){
//            boolQueryBuilderAll.must(QueryBuilders.matchPhraseQuery("invalid","1")).must(boolQueryBuilder);
//        }
//        //根据view功能性算分
//        FieldValueFactorFunctionBuilder fieldValueFactorFunctionBuilder = new FieldValueFactorFunctionBuilder("view");
//        fieldValueFactorFunctionBuilder.factor(0.5f);
//
//        //最终的查询语句
//        QueryBuilder queryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilderAll, fieldValueFactorFunctionBuilder)
//                .boostMode(CombineFunction.SUM);
//
//        //构建查询
//        searchSourceBuilder
//                .query(queryBuilder)
//                .from((page - 1) * limit)
//                .size(limit);
//
//        SearchResult searchResult = jestSearchUtil.query(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), searchSourceBuilder.toString());
//
//        //为了返回id
//        List<SearchResult.Hit<Knowledge, Void>> hits = searchResult.getHits(Knowledge.class);
//
//        Map<String, Object> pageDataResult = new HashMap<>(2);
//        pageDataResult.put("count", searchResult.getTotal());
//        pageDataResult.put("list", hits);
//
//        return new Message().ok().addData("data", pageDataResult);
//    }
//
//    @Override
//    public Message keywordsPageList(Integer page, Integer limit, String keywords) {
//        //title、outline、content之间should，关键词must
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//
//        //构建关键词匹配
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        BoolQueryBuilder titleBoolQueryBuilder = QueryBuilders.boolQuery();
//        BoolQueryBuilder outlineBoolQueryBuilder = QueryBuilders.boolQuery();
//        BoolQueryBuilder contentBoolQueryBuilder = QueryBuilders.boolQuery();
//
//        //关键词must
//        List<String> keywordList = StrUtil.split(keywords, ',');
//        keywordList.stream().forEach(words -> {
//            titleBoolQueryBuilder.must(QueryBuilders.matchQuery("title", words).boost(4));
//            outlineBoolQueryBuilder.must(QueryBuilders.matchQuery("outline", words).boost(2));
//            contentBoolQueryBuilder.must(QueryBuilders.matchQuery("content", words).boost(1));
//        });
//
//        boolQueryBuilder.should(titleBoolQueryBuilder).should(outlineBoolQueryBuilder).should(contentBoolQueryBuilder);
//
//        //根据view功能性算分
//        FieldValueFactorFunctionBuilder fieldValueFactorFunctionBuilder = new FieldValueFactorFunctionBuilder("view");
//        fieldValueFactorFunctionBuilder.factor(0.5f);
//
//        //最终的查询语句
//        QueryBuilder queryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, fieldValueFactorFunctionBuilder)
//                .boostMode(CombineFunction.SUM);
//
//        //构建高亮
//        HighlightBuilder highlightBuilder = new HighlightBuilder();
//        highlightBuilder.field("title").field("outline").field("content").numOfFragments(0);    //返回原定长度文本
//        highlightBuilder.preTags("<em>").postTags("</em>");//高亮标签
//
//        //构建查询
//        searchSourceBuilder
//                .query(queryBuilder)
//                .from((page - 1) * limit)
//                .size(limit)
//                .highlighter(highlightBuilder);
//
//        SearchResult searchResult = jestSearchUtil.query(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), searchSourceBuilder.toString());
//
//        //为了返回id
//        List<SearchResult.Hit<Knowledge, Void>> hits = searchResult.getHits(Knowledge.class);
//
//        //高亮文本缩略处理
//        hits.stream().forEach(hit -> {
//            Map<String, List<String>> highlight = hit.highlight;
//            if(ObjectUtil.isNotEmpty(highlight)){
//                List<String> contents = highlight.get("content");
//                if(ObjectUtil.isNotEmpty(contents)){
//                    String content = contents.get(0);
//                    String contentHandle = StringUtil.abridgeText(content, "<em>");
//                    hit.highlight.put("contentHandle", Arrays.asList(contentHandle));
//                }
//            }
//        });
//
//        Map<String, Object> pageDataResult = new HashMap<>(2);
//        pageDataResult.put("count", searchResult.getTotal());
//        pageDataResult.put("list", hits);
//
//        return new Message().ok().addData("data", pageDataResult);
//    }
//
//    @Override
//    public Knowledge getByEsId(String esId) {
//        Assert.isTrue(ObjectUtil.isNotEmpty(esId), "esId不空");
//        Knowledge knowledge = (Knowledge) jestSearchUtil.getById(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esId, Knowledge.class);
//        //浏览量+1
//        log.info("ES文档详情浏览量计数+1：" + esId);
//        redisTemplate.opsForHash().increment(RedisKey.KNOWLEDGE_VIEWS, esId, 1);
//        return knowledge;
//    }
//
//    @Transactional(rollbackFor=Exception.class)
//    @Override
//    public boolean insert(Knowledge knowledge) {
//        Assert.isTrue(ObjectUtil.isNotEmpty(knowledge), "数据不空");
//        //新增 关键字 前缀树
//        try {
//            RedisLock redisLock = new RedisLock(stringRedisTemplate, RedisKey.KEYWORD_OP);
//            redisLock.handle(o -> {
//                //新增到es
//                String esId = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN + StrUtil.UNDERLINE + RandomUtil.randomNumbers(9));
//                String currentDateTime = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN);
//                knowledge.setCreateTime(currentDateTime).setUpdateTime(currentDateTime);
//
//                //知识库图片附件处理(base64保存为文件，得到文件绝对路径)
//                esImageHandle(esId, knowledge);
//
//                EsUpdaeDocAction insert = jestUpdateDocUtil.insert(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esId, knowledge);
//
//                //新增失败，保存文件的操作撤销
//                jestUpdateDocUtil.assertIsOpSuccess(insert, "知识库-es新增失败", (x) -> esImageDelete(esId));
//
//                //维护mysql，关键字
//                List<Keywords> keywordsList = new ArrayList<>();
//                if(ObjectUtil.isNotEmpty(knowledge.getKeywords())){
//                    knowledge.getKeywords().stream().forEach(ketWord -> {
//                        Keywords keywords = new Keywords();
//                        keywords.setEsId(esId).setWords(ketWord).setCreateTime(new Date()).setUpdateTime(new Date());
//                        keywordsList.add(keywords);
//                    });
//                }
//                if(ObjectUtil.isNotEmpty(keywordsList)){
//                    this.keywordsMapper.insertBatch(keywordsList);
//                }
//                //维护关键词
//                KeyWordUtil.setPrefixTreeMap(knowledge.getKeywords());
//            });
//        } catch (InterruptedException e){
//            throw new EsModularException("获取redis锁超时-维护前缀树失败\t" + e.getMessage());
//        } catch (Exception e) {
//            throw new EsModularException("新增失败：\t" + e.getMessage());
//        }
//        return true;
//    }
//
//    @Transactional(rollbackFor=Exception.class)
//    @Override
//    public boolean delete(String esId, String keywords) {
//        AtomicInteger res = new AtomicInteger();
//        //清除 关键字 前缀树
//        RedisLock redisLock = new RedisLock(stringRedisTemplate, RedisKey.KEYWORD_OP);
//        try {
//            redisLock.handle(o -> {
//                List<String> keywordList = StrUtil.split(keywords, ',');
//                HashSet<String> keywordSet = new HashSet<>(keywordList);
//
//                EsUpdaeDocAction delete = jestUpdateDocUtil.delete(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esId);
//
//                //没有文档，则删除文件夹
//                jestUpdateDocUtil.assertIsOpSuccess(delete, "知识库-es删除失败，未找到该文档", (x) -> esImageDelete(esId));
//
//                int rs = this.keywordsMapper.deleteByExample(
//                        Example.builder(Keywords.class).where(Sqls.custom().andEqualTo("esId", esId)).build()
//                );
//                res.set(rs);
//
//                //维护关键词
//                KeyWordUtil.deletePrefixTreeMap(keywordSet);
//
//                //知识库图片删除
//                esImageDelete(esId);
//
//            });
//        } catch (InterruptedException e) {
//            throw new EsModularException("获取redis锁超时-维护前缀树失败\t" + e.getMessage());
//        } catch (Exception e) {
//            throw new EsModularException("删除失败：\t" + e.getMessage());
//        }
//        return res.get() > 0;
//    }
//
//    @Transactional(rollbackFor=Exception.class)
//    @Override
//    public boolean deleteBatch(List<String> esIds, Set<String> keywords) {
//        Assert.isTrue(ObjectUtil.isNotEmpty(esIds), "esIds不空");
//        AtomicInteger res = new AtomicInteger();
//        //清除 关键字 前缀树
//        try {
//            RedisLock redisLock = new RedisLock(stringRedisTemplate, RedisKey.KEYWORD_OP);
//            redisLock.handle(o -> {
//                EsUpdaeBatchDocAction esUpdaeBatchDocAction = jestUpdateDocUtil.deleteBatch(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esIds);
//
//                jestUpdateDocUtil.assertIsOpSuccess(esUpdaeBatchDocAction, "知识库-es批量删除失败，未找到该文档");
//
//                int rs = this.keywordsMapper.deleteByExample(
//                        Example.builder(Keywords.class).where(Sqls.custom().andIn("esId", esIds)).build()
//                );
//                res.set(rs);
//
//                //维护关键词
//                KeyWordUtil.deletePrefixTreeMap(keywords);
//
//                //知识库图片删除
//                esIds.stream().forEach(esId ->  esImageDelete(esId));
//
//            });
//        } catch (InterruptedException e) {
//            throw new EsModularException("获取redis锁超时-维护前缀树失败\t" + e.getMessage());
//        } catch (Exception e) {
//            throw new EsModularException("批量删除失败：\t" + e.getMessage());
//        }
//        return res.get() > 0;
//    }
//
//    @Transactional(rollbackFor=Exception.class)
//    @Override
//    public boolean update(String esId, Knowledge knowledge) {
//        Assert.isTrue(ObjectUtil.isNotEmpty(knowledge), "数据不空");
//        //更新 关键字 前缀树
//        try {
//            RedisLock redisLock = new RedisLock(stringRedisTemplate, RedisKey.KEYWORD_OP);
//            redisLock.handle(o -> {
//                //浏览量不给修改
//                knowledge.setView(null).setUpdateTime(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
//
//                //知识库图片附件处理(base64保存为文件，得到文件绝对路径)
//                esImageHandle(esId, knowledge);
//
//                EsUpdaeDocAction update = jestUpdateDocUtil.update(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esId, knowledge);
//
//                jestUpdateDocUtil.assertIsOpSuccess(update, "知识库-es修改失败");
//
//                //先批量全删除，在新增
//                this.keywordsMapper.deleteByExample(
//                        Example.builder(Keywords.class).where(Sqls.custom().andEqualTo("esId", esId)).build()
//                );
//
//                //维护mysql，关键字
//                List<Keywords> keywordsList = new ArrayList<>();
//                if(ObjectUtil.isNotEmpty(knowledge.getKeywords())){
//                    knowledge.getKeywords().stream().forEach(ketWord -> {
//                        Keywords keywords = new Keywords();
//                        keywords.setEsId(esId).setWords(ketWord).setCreateTime(new Date()).setUpdateTime(new Date());
//                        keywordsList.add(keywords);
//                    });
//                }
//                if(ObjectUtil.isNotEmpty(keywordsList)){
//                    this.keywordsMapper.insertBatch(keywordsList);
//                }
//                //维护关键词
//                KeyWordUtil.deletePrefixTreeMap(knowledge.getKeywords());
//                KeyWordUtil.setPrefixTreeMap(knowledge.getKeywords());
//            });
//        } catch (InterruptedException e) {
//            throw new EsModularException("获取redis锁超时-维护前缀树失败\t" + e.getMessage());
//        } catch (Exception e) {
//            throw new EsModularException("修改失败：\t" + e.getMessage());
//        }
//        return true;
//    }
//
//    /**
//     * 知识库图片附件处理
//     * @param esId
//     * @param knowledge
//     */
//    public void esImageHandle(String esId, Knowledge knowledge){
//        Knowledge.Files files = knowledge.getFiles();
//        if(files != null){
//            String image1 = files.getImage1();
//            files.setImage1(esImageHandle(esId, "image1", image1));
//            String image2 = files.getImage2();
//            files.setImage2(esImageHandle(esId, "image2", image2));
//            String image3 = files.getImage3();
//            files.setImage3(esImageHandle(esId, "image3", image3));
//            String image4 = files.getImage4();
//            files.setImage4(esImageHandle(esId, "image4", image4));
//            String image5 = files.getImage5();
//            files.setImage5(esImageHandle(esId, "image5", image5));
//            String image6 = files.getImage6();
//            files.setImage6(esImageHandle(esId, "image6", image6));
//            String image7 = files.getImage7();
//            files.setImage7(esImageHandle(esId, "image7", image7));
//            String image8 = files.getImage8();
//            files.setImage8(esImageHandle(esId, "image8", image8));
//        }
//    }
//
//    /**
//     * 知识库图片附件处理 base64存本地文件，返回文件绝对地址
//     * @param esId
//     * @param fileName
//     * @param imageBase64
//     * @return
//     */
//    public String esImageHandle(String esId, String fileName, String imageBase64){
//        String filePath = "";
//        try {
//            if(ObjectUtil.isNotNull(imageBase64) && "".equals(imageBase64)){
//                return "";
//            }
//            if(ObjectUtil.isNotEmpty(imageBase64)){
//                MultipartFile multipartFile = Base64DecodedMultipartFile.base64ToMultipart(imageBase64);
//                String rootPath = sysFileConfig.getKnowledgeRootPath() + File.separator + esId;
//                filePath = fileService.fileUpload(multipartFile, rootPath, fileName, sysFileConfig.getKnowledgeTypes(), sysFileConfig.getKnowledgeMaxSize());
//            }
//        } catch (Exception e) {
//            log.error("KnowledgeServiceImpl-esImageHandle异常:", e);
//        }
//        return filePath;
//    }
//
//    /**
//     * 知识库图片删除
//     * @param esId
//     */
//    public void esImageDelete(String esId){
//        String rootPath = sysFileConfig.getKnowledgeRootPath() + File.separator + esId;
//        FileUtil.del(rootPath);
//    }
//
//    /**
//     * 逻辑删除知识库
//     *
//     * @param esId
//     * @return
//     */
//    @Override
//    public boolean fakeDelete(String esId) {
//        String now = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN);
//        Knowledge knowledge = new Knowledge();
//        knowledge.setInvalid(INVALID).setInvalidTime(now);
//        EsUpdaeDocAction update = jestUpdateDocUtil.update(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esId, knowledge);
//        jestUpdateDocUtil.assertIsOpSuccess(update, "更新知识库失败！");
//        return true;
//    }
//
//    /**
//     * 批量逻辑删除知识库
//     *
//     * @param esIds
//     * @return
//     */
//    @Override
//    public boolean fakeDeleteBatch(List<String> esIds) {
//        String now = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN);
//        Knowledge knowledge = new Knowledge();
//        knowledge.setInvalid(INVALID).setInvalidTime(now);
//        for (String esId : esIds) {
//            EsUpdaeDocAction update = jestUpdateDocUtil.update(EsIndexTypeEnum.KNOWLEDGE.getIndex(), EsIndexTypeEnum.KNOWLEDGE.getType(), esId, knowledge);
//            jestUpdateDocUtil.assertIsOpSuccess(update, "更新知识库失败！");
//        }
//        return true;
//    }
//}
